package com.zp.self.module.level_4_算法练习.数据结构.链表;

import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

/**
 * @author By ZengPeng
 */
public class 力扣_138_复制带随机指针的链表 {
    @Test
    public void main() {

        System.out.println(copyRandomList(new Node(1)));
        System.out.println(copyRandomList(null));
    }
    class Node {
        int val;
        Node next;
        Node random;

        public Node(int val) {
            this.val = val;
            this.next = null;
            this.random = null;
        }
    }
    /**
    题目：给你一个长度为 n 的链表，每个节点包含一个额外增加的随机指针 random ，该指针可以指向链表中的任何节点或空节点。
     构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成，其中每个新节点的值都设为其对应的原节点的值。
     新节点的 next 指针和 random 指针也都应指向复制链表中的新节点，并使原链表和复制链表中的这些指针能够表示相同的链表状态。
     复制链表中的指针都不应指向原链表中的节点 。
     例如，如果原链表中有 X 和 Y 两个节点，其中 X.random --> Y 。
     那么在复制链表中对应的两个节点 x 和 y ，同样有 x.random --> y 。返回复制链表的头节点。
     用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示：
     val：一个表示 Node.val 的整数。
     random_index：随机指针指向的节点索引（范围从 0 到 n-1）；如果不指向任何节点，则为  null 。
     你的代码 只 接受原链表的头节点 head 作为传入参数。

     示例 1：
     输入：head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
     输出：[[7,null],[13,0],[11,4],[10,2],[1,0]]

     示例 2：
     输入：head = [[1,1],[2,1]]
     输出：[[1,1],[2,1]]

     示例 3：
     输入：head = [[3,null],[3,0],[3,null]]
     输出：[[3,null],[3,0],[3,null]]



    分析：【P 💔💔】
       1.Hash存储：先遍历链表的next创建出新的链表，创建Map《旧Node,新Node》,因为next是一条道走到黑的。
                    而如果先用random 则可能会出现环，不易处理
                    --执行用时：0 ms, 在所有 Java 提交中击败了100.00%的用户
                    --时长：8分钟
       大神：在每个原节点.next =克隆节点,然后再将链表拆开。--空间复杂度：O(1)

    边界值 & 注意点：
       1.
     **/
    public Node copyRandomList(Node head) {
        if(head==null) return null;
        Map<Node,Node> old_new_map = new HashMap<>();
        Node res = new Node(head.val),pro=res;
        old_new_map.put(head,res);
        while (head.next!=null){
            head =  head.next;
            Node newNode = new Node(head.val);
            pro.next= newNode;
            old_new_map.put(head,newNode);
            pro = pro.next;
        }
        for (Map.Entry<Node, Node> entry : old_new_map.entrySet()) {
            Node random = entry.getKey().random;
            if(random!=null)
                entry.getValue().random = old_new_map.get(random);
        }
        return res;
    }
}
